JavaScript Dekoratorlariga chuqur kirish, ularning sintaksisi, metadata dasturlashdagi qo'llanilishi, eng yaxshi amaliyotlar va kodning saqlanuvchanligiga ta'siri. Amaliy misollar va kelajakdagi mulohazalarni o'z ichiga oladi.
JavaScript Dekoratorlari: Metadata Dasturlashni Amalga Oshirish
JavaScript Dekoratorlari bu klasslar, metodlar, xususiyatlar va parametrlarga metadata qo'shish va ularning xatti-harakatini deklarativ va qayta ishlatiladigan tarzda o'zgartirish imkonini beruvchi kuchli xususiyatdir. Ular ECMAScript standartlashtirish jarayonida 3-bosqich taklifi bo'lib, o'zining (bir oz farqli) implementatsiyasiga ega bo'lgan TypeScript bilan keng qo'llaniladi. Ushbu maqola JavaScript Dekoratorlari haqida keng qamrovli ma'lumot beradi, ularning metadata dasturlashdagi rolini yoritadi va amaliy misollar bilan qo'llanilishini ko'rsatadi.
JavaScript Dekoratorlari nima?
Dekoratorlar - bu obyektning tuzilishini o'zgartirmasdan uning funksionalligini oshiradigan yoki o'zgartiradigan dizayn shablonidir. JavaScript-da dekoratorlar klasslar, metodlar, aksessorlar, xususiyatlar yoki parametrlarga biriktirilishi mumkin bo'lgan maxsus turdagi deklaratsiyalardir. Ular dekoratsiya qilingan element aniqlanganda bajariladigan funksiyadan keyin @ belgisidan foydalanadilar.
Dekoratorlarni dekoratsiya qilingan elementni kirish sifatida qabul qiladigan va shu elementning o'zgartirilgan versiyasini qaytaradigan yoki unga asoslanib qandaydir qo'shimcha ta'sir ko'rsatadigan funksiyalar deb o'ylang. Bu asl klass yoki funksiyani to'g'ridan-to'g'ri o'zgartirmasdan funksionallik qo'shishning toza va nafis usulini taqdim etadi.
Asosiy Tushunchalar:
- Dekorator Funksiyasi:
@belgisi oldidan keladigan funksiya. U dekoratsiya qilingan element haqida ma'lumot oladi va uni o'zgartirishi mumkin. - Dekoratsiya qilingan Element: Dekoratsiya qilingan klass, metod, aksessor, xususiyat yoki parametr.
- Metadata: Ma'lumotlarni tavsiflovchi ma'lumotlar. Dekoratorlar ko'pincha metadata-ni kod elementlari bilan bog'lash uchun ishlatiladi.
Sintaksis va Tuzilma
Dekoratorning asosiy sintaksisi quyidagicha:
@decorator
class MyClass {
// Class members
}
Bu yerda @decorator dekorator funksiyasi va MyClass dekoratsiya qilingan klassdir. Dekorator funksiyasi klass aniqlanganda chaqiriladi va klass ta'rifiga kirish va uni o'zgartirish imkoniyatiga ega.
Dekoratorlar, shuningdek, dekorator funksiyasining o'ziga uzatiladigan argumentlarni qabul qilishi mumkin:
@loggable(true, "Custom Message")
class MyClass {
// Class members
}
Bu holda, loggable argumentlarni qabul qiladigan va haqiqiy dekorator funksiyasini qaytaradigan dekorator zavodi funksiyasidir. Bu yanada moslashuvchan va sozlanishi mumkin bo'lgan dekoratorlarni yaratish imkonini beradi.
Dekoratorlarning Turlari
Dekoratorlarning ular nima dekoratsiya qilishiga qarab har xil turlari mavjud:
- Klass Dekoratorlari: Klasslarga qo'llaniladi.
- Metod Dekoratorlari: Klass ichidagi metodlarga qo'llaniladi.
- Aksessor Dekoratorlari: Getter va setter aksessorlariga qo'llaniladi.
- Xususiyat Dekoratorlari: Klass xususiyatlariga qo'llaniladi.
- Parametr Dekoratorlari: Metod parametrlariga qo'llaniladi.
Klass Dekoratorlari
Klass dekoratorlari klassning xatti-harakatini o'zgartirish yoki yaxshilash uchun ishlatiladi. Ular klass konstruktorini argument sifatida qabul qiladi va asl konstruktorni almashtirish uchun yangi konstruktor qaytarishi mumkin. Bu sizga log yozish, bog'liqlikni kiritish yoki holatni boshqarish kabi funksionalliklarni qo'shish imkonini beradi.
Misol:
function loggable(constructor: Function) {
console.log("Class " + constructor.name + " was created.");
}
@loggable
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}
const user = new User("Alice"); // Chiqaradi: Class User was created.
Ushbu misolda, loggable dekoratori User klassining yangi namunasi yaratilganda konsolga xabar chiqaradi. Bu disk raskadrovka yoki monitoring uchun foydali bo'lishi mumkin.
Metod Dekoratorlari
Metod dekoratorlari klass ichidagi metodning xatti-harakatini o'zgartirish uchun ishlatiladi. Ular quyidagi argumentlarni qabul qiladi:
target: Klassning prototipi.propertyKey: Metodning nomi.descriptor: Metod uchun xususiyat deskriptori.
Deskriptor sizga metodning xatti-harakatiga kirish va uni o'zgartirish, masalan, uni qo'shimcha mantiq bilan o'rash yoki butunlay qayta aniqlash imkonini beradi.
Misol:
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling method ${propertyKey} with arguments: ${args}`);
const result = originalMethod.apply(this, args);
console.log(`Method ${propertyKey} returned: ${result}`);
return result;
};
return descriptor;
}
class Calculator {
@logMethod
add(a: number, b: number): number {
return a + b;
}
}
const calculator = new Calculator();
const sum = calculator.add(5, 3); // Metod chaqiruvi va qaytariladigan qiymat uchun loglarni chiqaradi
Ushbu misolda, logMethod dekoratori metodning argumentlari va qaytariladigan qiymatini log qiladi. Bu disk raskadrovka va unumdorlikni kuzatish uchun foydali bo'lishi mumkin.
Aksessor Dekoratorlari
Aksessor dekoratorlari metod dekoratorlariga o'xshaydi, lekin getter va setter aksessorlariga qo'llaniladi. Ular metod dekoratorlari bilan bir xil argumentlarni qabul qiladi va aksessorning xatti-harakatini o'zgartirishga imkon beradi.
Misol:
function validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalSet = descriptor.set;
descriptor.set = function (value: any) {
if (value < 0) {
throw new Error("Value must be non-negative.");
}
originalSet.call(this, value);
};
}
class Temperature {
private _celsius: number;
constructor(celsius: number) {
this._celsius = celsius;
}
@validate
set celsius(value: number) {
this._celsius = value;
}
get celsius(): number {
return this._celsius;
}
}
const temperature = new Temperature(25);
temperature.celsius = 30; // To'g'ri
// temperature.celsius = -10; // Xatolik chiqaradi
Ushbu misolda, validate dekoratori harorat qiymatining manfiy emasligini ta'minlaydi. Bu ma'lumotlar yaxlitligini ta'minlash uchun foydali bo'lishi mumkin.
Xususiyat Dekoratorlari
Xususiyat dekoratorlari klass xususiyatining xatti-harakatini o'zgartirish uchun ishlatiladi. Ular quyidagi argumentlarni qabul qiladi:
target: Klassning prototipi (namuna xususiyatlari uchun) yoki klass konstruktori (statik xususiyatlar uchun).propertyKey: Xususiyatning nomi.
Xususiyat dekoratorlari metadata-ni aniqlash yoki xususiyatning deskriptorini o'zgartirish uchun ishlatilishi mumkin.
Misol:
function readonly(target: any, propertyKey: string) {
Object.defineProperty(target, propertyKey, {
writable: false,
});
}
class Configuration {
@readonly
apiUrl: string = "https://api.example.com";
}
const config = new Configuration();
// config.apiUrl = "https://newapi.example.com"; // Qattiq rejimda xatolik chiqaradi
Ushbu misolda, readonly dekoratori apiUrl xususiyatini faqat o'qish uchun qiladi, bu esa uning ishga tushirilgandan keyin o'zgartirilishini oldini oladi. Bu o'zgarmas konfiguratsiya qiymatlarini aniqlash uchun foydali bo'lishi mumkin.
Parametr Dekoratorlari
Parametr dekoratorlari metod parametrining xatti-harakatini o'zgartirish uchun ishlatiladi. Ular quyidagi argumentlarni qabul qiladi:
target: Klassning prototipi (namuna metodlari uchun) yoki klass konstruktori (statik metodlar uchun).propertyKey: Metodning nomi.parameterIndex: Metodning parametrlar ro'yxatidagi parametr indeksi.
Parametr dekoratorlari boshqa turdagi dekoratorlarga qaraganda kamroq ishlatiladi, lekin ular kirish parametrlarini tekshirish yoki bog'liqliklarni kiritish uchun foydali bo'lishi mumkin.
Misol:
function required(target: any, propertyKey: string, parameterIndex: number) {
const existingRequiredParameters: number[] = Reflect.getOwnMetadata(propertyKey, target, "required") || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata(propertyKey, existingRequiredParameters, target, "required");
}
function validateMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) {
let method = descriptor.value!;
descriptor.value = function () {
let requiredParameters: number[] = Reflect.getOwnMetadata(propertyName, target, "required");
if (requiredParameters) {
for (let parameterIndex of requiredParameters) {
if (arguments[parameterIndex] === null || arguments[parameterIndex] === undefined) {
throw new Error(`Missing required argument at index ${parameterIndex}`);
}
}
}
return method.apply(this, arguments);
};
}
class ArticleService {
create(
@required title: string,
@required content: string
): void {
console.log(`Creating article with title: ${title} and content: ${content}`);
}
}
const service = new ArticleService();
// service.create("My Article", null); // Xatolik chiqaradi
service.create("My Article", "Article Content"); // To'g'ri
Ushbu misolda, required dekoratori parametrlarni majburiy deb belgilaydi va validateMethod dekoratori bu parametrlarning null yoki undefined emasligini ta'minlaydi. Bu metodga kiritiladigan ma'lumotlarni tekshirishni majburiy qilish uchun foydali bo'lishi mumkin.
Dekoratorlar yordamida Metadata Dasturlash
Dekoratorlarning eng kuchli qo'llanilish holatlaridan biri bu metadata dasturlashdir. Metadata - bu ma'lumotlar haqidagi ma'lumot. Dasturlash kontekstida bu sizning kodingizning tuzilishi, xatti-harakati va maqsadini tavsiflovchi ma'lumotlardir. Dekoratorlar metadata-ni klasslar, metodlar, xususiyatlar va parametrlar bilan bog'lashning toza va deklarativ usulini taqdim etadi.
Reflect Metadata API
Reflect Metadata API - bu obyektlar bilan bog'liq metadata-ni saqlash va olish imkonini beruvchi standart API. U quyidagi funksiyalarni taqdim etadi:
Reflect.defineMetadata(key, value, target, propertyKey): Obyektning ma'lum bir xususiyati uchun metadata-ni aniqlaydi.Reflect.getMetadata(key, target, propertyKey): Obyektning ma'lum bir xususiyati uchun metadata-ni oladi.Reflect.hasMetadata(key, target, propertyKey): Obyektning ma'lum bir xususiyati uchun metadata mavjudligini tekshiradi.Reflect.deleteMetadata(key, target, propertyKey): Obyektning ma'lum bir xususiyati uchun metadata-ni o'chiradi.
Siz bu funksiyalarni dekoratorlar bilan birgalikda kod elementlaringizga metadata-ni bog'lash uchun ishlatishingiz mumkin.
Misol: Metadata-ni Aniqlash va Olish
import 'reflect-metadata';
const logKey = "log";
function log(message: string) {
return function (target: any, key: string, descriptor: PropertyDescriptor) {
Reflect.defineMetadata(logKey, message, target, key);
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(Reflect.getMetadata(logKey, target, key));
const result = originalMethod.apply(this, args);
return result;
}
return descriptor;
}
}
class Example {
@log("Executing method")
myMethod(arg: string): string {
return `Method called with ${arg}`;
}
}
const example = new Example();
example.myMethod("Hello"); // Chiqaradi: Executing method, Method called with Hello
Ushbu misolda, log dekoratori Reflect Metadata API-dan foydalanib, myMethod metodiga log xabarini bog'laydi. Metod chaqirilganda, dekorator xabarni oladi va konsolga chiqaradi.
Metadata Dasturlashning Qo'llanilish Holatlari
Dekoratorlar bilan metadata dasturlashning ko'plab amaliy qo'llanilishlari mavjud, jumladan:
- Serializatsiya va Deserializatsiya: Xususiyatlarni JSON yoki boshqa formatlarga/formatlardan qanday serializatsiya qilinishi yoki deserializatsiya qilinishini boshqarish uchun metadata bilan izohlang. Bu tashqi APIlar yoki ma'lumotlar bazalaridan olingan ma'lumotlar bilan ishlashda, ayniqsa turli platformalar bo'ylab ma'lumotlarni o'zgartirishni talab qiladigan taqsimlangan tizimlarda (masalan, turli mintaqaviy standartlar o'rtasida sana formatlarini o'zgartirish) foydali bo'lishi mumkin. Xalqaro yuk tashish manzillari bilan shug'ullanadigan elektron tijorat platformasini tasavvur qiling, u yerda siz har bir mamlakat uchun to'g'ri manzil formati va tekshirish qoidalarini belgilash uchun metadata-dan foydalanishingiz mumkin.
- Bog'liqliklarni Kiritish (Dependency Injection): Klassga kiritilishi kerak bo'lgan bog'liqliklarni aniqlash uchun metadata-dan foydalaning. Bu bog'liqliklarni boshqarishni soddalashtiradi va bo'sh bog'lanishni (loose coupling) rag'batlantiradi. Bir-biriga bog'liq bo'lgan xizmatlarga ega mikroservislar arxitekturasini ko'rib chiqing. Dekoratorlar va metadata konfiguratsiyaga asoslangan holda servis mijozlarini dinamik ravishda kiritishni osonlashtirishi mumkin, bu esa osonroq masshtablash va nosozliklarga chidamlilikni ta'minlaydi.
- Validatsiya: Validatsiya qoidalarini metadata sifatida aniqlang va ma'lumotlarni avtomatik ravishda tekshirish uchun dekoratorlardan foydalaning. Bu ma'lumotlar yaxlitligini ta'minlaydi va shablon kodni kamaytiradi. Masalan, global moliya ilovasi turli mintaqaviy moliyaviy qoidalarga rioya qilishi kerak. Metadata foydalanuvchining joylashuviga qarab valyuta formatlari, soliq hisob-kitoblari va tranzaksiya limitlari uchun validatsiya qoidalarini belgilashi mumkin, bu esa mahalliy qonunlarga muvofiqlikni ta'minlaydi.
- Marshrutlash va Oradagi Dasturiy Ta'minot (Middleware): Veb-ilovalar uchun marshrutlar va oradagi dasturiy ta'minotni aniqlash uchun metadata-dan foydalaning. Bu ilovangizni sozlashni soddalashtiradi va uni yanada saqlanuvchan qiladi. Global taqsimlangan kontent yetkazib berish tarmog'i (CDN) kontent turiga va foydalanuvchining joylashuviga qarab keshlash siyosati va marshrutlash qoidalarini aniqlash uchun metadata-dan foydalanishi mumkin, bu esa butun dunyo bo'ylab foydalanuvchilar uchun unumdorlikni optimallashtiradi va kechikishni kamaytiradi.
- Avtorizatsiya va Autentifikatsiya: Rollarni, ruxsatlarni va autentifikatsiya talablarini metodlar va klasslar bilan bog'lang, bu esa deklarativ xavfsizlik siyosatini osonlashtiradi. Turli bo'limlar va joylarda xodimlari bo'lgan ko'p millatli korporatsiyani tasavvur qiling. Dekoratorlar foydalanuvchining roli, bo'limi va joylashuviga qarab kirishni boshqarish qoidalarini belgilashi mumkin, bu esa faqat vakolatli xodimlar maxfiy ma'lumotlar va funksiyalarga kirishini ta'minlaydi.
Eng Yaxshi Amaliyotlar
JavaScript Dekoratorlaridan foydalanganda quyidagi eng yaxshi amaliyotlarni hisobga oling:
- Dekoratorlarni Sodda Saqlang: Dekoratorlar diqqat markazida bo'lishi va bitta, aniq belgilangan vazifani bajarishi kerak. O'qish qulayligi va saqlanuvchanlikni saqlash uchun dekoratorlar ichida murakkab mantiqdan saqlaning.
- Dekorator Zavodlaridan Foydalaning: Sozlanishi mumkin bo'lgan dekoratorlarni yaratish uchun dekorator zavodlaridan foydalaning. Bu sizning dekoratorlaringizni yanada moslashuvchan va qayta ishlatiladigan qiladi.
- Qo'shimcha Ta'sirlardan Saqlaning: Dekoratorlar asosan dekoratsiya qilingan elementni o'zgartirishga yoki unga metadata-ni bog'lashga e'tibor qaratishi kerak. Kodingizni tushunish va disk raskadrovka qilishni qiyinlashtirishi mumkin bo'lgan dekoratorlar ichida murakkab qo'shimcha ta'sirlarni bajarishdan saqlaning.
- TypeScript-dan Foydalaning: TypeScript dekoratorlar uchun ajoyib qo'llab-quvvatlashni, jumladan turlarni tekshirish va IntelliSense-ni taqdim etadi. TypeScript-dan foydalanish xatolarni erta aniqlashga yordam beradi va dasturlash tajribangizni yaxshilaydi.
- Dekoratorlaringizni Hujjatlashtiring: Dekoratorlaringizning maqsadi va ulardan qanday foydalanish kerakligini tushuntirish uchun ularni aniq hujjatlashtiring. Bu boshqa dasturchilar uchun dekoratorlaringizni tushunish va to'g'ri ishlatishni osonlashtiradi.
- Unumdorlikni Hisobga Oling: Dekoratorlar kuchli bo'lsa-da, ular unumdorlikka ham ta'sir qilishi mumkin. Dekoratorlaringizning unumdorlikka ta'sirini, ayniqsa unumdorlik muhim bo'lgan ilovalarda yodda tuting.
Dekoratorlar yordamida Xalqarolashtirish Misollari
Dekoratorlar xalqarolashtirish (i18n) va mahalliylashtirish (l10n) ga yordam berishi mumkin, bu esa kod komponentlariga mahalliy ma'lumotlar va xatti-harakatlarni bog'lash orqali amalga oshiriladi:
Misol: Mahalliy Sana Formatlash
import 'reflect-metadata';
interface DateFormatOptions {
locale: string;
options?: Intl.DateTimeFormatOptions;
}
const dateFormatKey = 'dateFormat';
function formatDate(options: DateFormatOptions) {
return function(target: any, propertyKey: string) {
Reflect.defineMetadata(dateFormatKey, options, target, propertyKey);
};
}
class Event {
@formatDate({ locale: 'fr-FR', options: { year: 'numeric', month: 'long', day: 'numeric' } })
startDate: Date;
constructor(startDate: Date) {
this.startDate = startDate;
}
getFormattedStartDate(): string {
const options: DateFormatOptions = Reflect.getMetadata(dateFormatKey, Object.getPrototypeOf(this), 'startDate');
return this.startDate.toLocaleDateString(options.locale, options.options);
}
}
const event = new Event(new Date());
console.log(event.getFormattedStartDate()); // Sanani fransuz formatida chiqaradi
Misol: Foydalanuvchi Joylashuviga Asoslangan Valyuta Formatlash
import 'reflect-metadata';
interface CurrencyFormatOptions {
locale: string;
currency: string;
}
const currencyFormatKey = 'currencyFormat';
function formatCurrency(options: CurrencyFormatOptions) {
return function(target: any, propertyKey: string) {
Reflect.defineMetadata(currencyFormatKey, options, target, propertyKey);
};
}
class Product {
@formatCurrency({ locale: 'de-DE', currency: 'EUR' })
price: number;
constructor(price: number) {
this.price = price;
}
getFormattedPrice(): string {
const options: CurrencyFormatOptions = Reflect.getMetadata(currencyFormatKey, Object.getPrototypeOf(this), 'price');
return this.price.toLocaleString(options.locale, { style: 'currency', currency: options.currency });
}
}
const product = new Product(99.99);
console.log(product.getFormattedPrice()); // Narxni nemis yevro formatida chiqaradi
Kelajakdagi Mulohazalar
JavaScript dekoratorlari rivojlanayotgan xususiyat bo'lib, standart hali ham ishlab chiqilmoqda. Kelajakdagi ba'zi mulohazalarga quyidagilar kiradi:
- Standartlashtirish: Dekoratorlar uchun ECMAScript standarti hali ham davom etmoqda. Standart rivojlangan sari, dekoratorlarning sintaksisi va xatti-harakatlarida o'zgarishlar bo'lishi mumkin.
- Unumdorlikni Optimallashtirish: Dekoratorlar keng qo'llanila boshlagan sari, ularning ilova unumdorligiga salbiy ta'sir ko'rsatmasligini ta'minlash uchun unumdorlikni optimallashtirishga ehtiyoj paydo bo'ladi.
- Asboblarni Qo'llab-quvvatlash: Dekoratorlar uchun yaxshilangan asboblarni qo'llab-quvvatlash, masalan, IDE integratsiyasi va disk raskadrovka vositalari, dasturchilarga dekoratorlardan samarali foydalanishni osonlashtiradi.
Xulosa
JavaScript Dekoratorlari metadata dasturlashni amalga oshirish va kodingizning xatti-harakatini yaxshilash uchun kuchli vositadir. Dekoratorlardan foydalanib, siz funksionallikni toza, deklarativ va qayta ishlatiladigan tarzda qo'shishingiz mumkin. Bu yanada saqlanuvchan, sinovdan o'tkaziladigan va masshtablanadigan kodga olib keladi. Turli xil dekoratorlarni va ulardan samarali foydalanishni tushunish zamonaviy JavaScript dasturlash uchun muhimdir. Dekoratorlar, ayniqsa Reflect Metadata API bilan birlashtirilganda, bog'liqliklarni kiritish va validatsiyadan tortib serializatsiya va marshrutlashgacha bo'lgan bir qator imkoniyatlarni ochib beradi, bu esa kodingizni yanada ifodali va boshqarishni osonlashtiradi.